iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
2
Mobile Development

Android TDD 測試驅動開發系列 第 11

Day11 - Instrumented Tests

  • 分享至 

  • xImage
  •  

把所有跟Android framework的相依都用Mock去模擬及隔離,有時不見得是好的選擇。因為你不會知道在Android裝置上是不是真的可以執行。

在上一個範例SharePreference的測試,為了讓測試速度較快,我們用模擬物件來驗證Context、SharedPreference的互動,來讓這個測試能在JVM執行(如下圖)。

https://ithelp.ithome.com.tw/upload/images/20190925/20111896TL93nmsfS8.png

這一篇要來介紹另一個方法,將測試拆分為2個部分。首先,建立專門處理SharedPreference儲存資料的物件SharedPreferenceManager。所有的儲存資料都由這個類別處理。我們將寫一個Instrumented test來測試是否真的有將資料儲存進去,而非用Mock的方式。
對於原本的Repository.saveUserId的測試,只需要知道有成功呼叫ISharedPreferenceManger,並傳入正確的參數即可。

拆為2個測試:
Local Unit test
測試Repository.saveUserId 與 ISharedPreferenceManager的互動
Instrumented test
測試SharePreference是否有儲存成功。

https://ithelp.ithome.com.tw/upload/images/20190925/20111896UqfdyJ02q8.png

新增SharePreferenceManager,這個類別用來統一處理SharePreference儲存資料。
在這裡新增一個saveString、getString,只要是存取字串都可以用這個Manager來處理

class SharedPreferenceManager(override val context: Context) : ISharedPreferenceManager {
    private val sharedPreferenceKey = "USER_DATA"

    var sharedPreference: SharedPreferences

    init {
        sharedPreference = context.getSharedPreferences(sharedPreferenceKey, Context.MODE_PRIVATE)
    }

    override fun saveString(key: String, value: String){
        sharedPreference.edit().putString(key, value).commit()
    }

    override fun getString(key: String): String {
        return sharedPreference.getString(key, "")
    }
}

有了SharedPreferenceManager,Repository就可以直接呼叫SharedPreferenceManager來儲存使用者帳號。
class Repository(val sharedPreferenceManager: ISharedPreferenceManager) {

    fun saveUserId(id: String) {
        sharedPreferenceManager.saveString("USER_ID", id)
    }
}

Local Unit Test

驗證Repository是否有呼叫SharedPreferenceManager.saveString()

@Test
fun saveUserId() {

    val mockSharedPreferenceManager = mock(ISharedPreferenceManager::class.java)

    val userId = "A1234567"
    val preKey = "USER_ID"

    val repository = Repository(mockSharedPreferenceManager)

    //Act 呼叫repository.saveUserId()
    repository.saveUserId(userId)

    //Assert
    verify(mockSharedPreferenceManager).saveString(preKey, userId)
}

Instrumented Test

在Instrumented Test,就直接測試SharedPreference是否有儲存資料成功。

@RunWith(AndroidJUnit4::class)
class SharedPreferenceManagerTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getTargetContext()
        val key = "User_Id"
        val value = "A123456789"

        val sharedPreferenceManager: ISharedPreferenceManager = SharedPreferenceManager(appContext)
        sharedPreferenceManager.saveString(key, value)

        val valueFromSP = sharedPreferenceManager.getString(key)

        //將SharedPreference取出,驗證結果
        Assert.assertEquals(value, valueFromSP)
    }
}

執行測試,你可以看到Android studio會開啟模擬器或手機,表示這是一個Instrumented test。雖然這樣的測試較花時間,但我們已提出SharedPreferenceManager來處理所有的SharedPreference儲存資料,如果有別的欄位要儲存時,事實上是不需要再異動SharedPreferenceManger,也不需要新增額外的Android test。

不是遇到Android framework,就一定是用mock來處理。

以這個範例,只有SharedPreferenceManager我們需要用Instrumented test。在Repository我們改成了呼叫ISharedPreferenceManager這個介面,所以Repository仍可以用Unit test的方式來測試是否與Interface有正確的互動,也就是有呼叫saveString及傳送的參數也是正確。

在你的App中,你可能會經常使用SharedPreference來存取資料。在Repository我們保留Local Unit test來提高測試的效率。在SharedPreferenceManager,這裡就直接使用Instrumented test,較接近真實的情況。

範例下載:
https://github.com/evanchen76/InstrumentedTestSample


上一篇
Day10 - Mock Android Framework
下一篇
Day12 - UI 測試:使用Espresso
系列文
Android TDD 測試驅動開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言